package fmeter

import (
	"context"
	"time"

	"gitee.com/wu-jin-feng/fgin/fgin_plugs/fotel"
	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/metric"
)

const (
	defaultCounterName   = "fgin_otel_meter_reuqest_code_count"     // 默认的计数器名
	defaultHistogramName = "fgin_otel_meter_reuqest_seconds_bucket" // 默认的同步仪器名
)

type Meter struct {
	meter            metric.Meter
	defaultCounter   metric.Int64Counter
	defaultHistogram metric.Float64Histogram
}

// 新建一个meter
func NewMeter(name string) *Meter {
	if !fotel.GetMeterProviderStatus() {
		panic("fotel尚未初始化meterProvider")
	}
	meter := otel.Meter(name)
	// Counter 同步计数器
	defaultCounter, err := meter.Int64Counter(defaultCounterName, metric.WithUnit("{call}"))
	if err != nil {
		panic(err)
	}
	// Histogram 同步仪器
	defaultHistogram, err := meter.Float64Histogram(
		defaultHistogramName,
		metric.WithUnit("s"),
		metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.1, 0.250, 0.5, 1),
	)
	if err != nil {
		panic(err)
	}
	fmeter := &Meter{
		meter:            meter,
		defaultCounter:   defaultCounter,
		defaultHistogram: defaultHistogram,
	}
	return fmeter
}

// 获取meter
func (m *Meter) GetMeter() metric.Meter {
	return m.meter
}

// 获取默认计数器
func (m *Meter) GetDefaultCounter() metric.Int64Counter {
	return m.defaultCounter
}

// 获取默认计数器
func (m *Meter) GetDefaultHistogram() metric.Float64Histogram {
	return m.defaultHistogram
}

// 默认上报数据计数和耗时
func (m *Meter) DefaultMetric(ctx context.Context, startTime time.Time, kind, method, path, code string) {
	if v, ok := ctx.(*gin.Context); ok {
		ctx = v.Request.Context()
	}
	mAttr := metric.WithAttributes(
		attribute.String("kind", kind),
		attribute.String("method", method),
		attribute.String("path", path),
		attribute.String("code", code),
	)
	// 计数器
	m.defaultCounter.Add(ctx, 1, mAttr)
	// 耗时记录器
	m.defaultHistogram.Record(ctx, time.Since(startTime).Seconds(), mAttr)
}

// 计数器+1
func (m *Meter) CounterAdd(ctx context.Context, kind, method, path, code string) {
	if v, ok := ctx.(*gin.Context); ok {
		ctx = v.Request.Context()
	}
	m.defaultCounter.Add(ctx, 1, metric.WithAttributes(
		attribute.String("kind", kind),
		attribute.String("method", method),
		attribute.String("path", path),
		attribute.String("code", code),
	))
}

// 同步器记录耗时
func (m *Meter) HistogramSet(ctx context.Context, startTime time.Time, kind, method, path, code string) {
	if v, ok := ctx.(*gin.Context); ok {
		ctx = v.Request.Context()
	}
	m.defaultHistogram.Record(ctx, time.Since(startTime).Seconds(), metric.WithAttributes(attribute.String("kind", kind),
		attribute.String("method", method),
		attribute.String("path", path),
		attribute.String("code", code),
	))
}
